/*+*************************************************
Filename: spi_mic01/src/top.v
Description:
  Transfer mic data to ws63e through SPI interface. 
  Modified base on spi_master_test & mic02 project.

Modification:
  2024.09.22 creation by H.Zheng

*************************************************-*/



module top (
    input sys_clk,          // clk input  27MHz
    input sys_rst_n,        // button as reset
    input button1,          // user button
    input uart_rx,          // usb uart
    output uart_tx,         // usb uart
    output wire [5:0] led,    // 6 LEDS pin
    output wire mic_ws,
    output wire mic_ck,
    output wire mic_lr,
    input wire mic_data,
    output wire ws63_clk,
    input wire ws63_data_out,
    output wire ws63_data_in,
    output wire ws63_cs_n
);

assign uart_tx = 1'b1;


  wire spi_clk, spi_cs_n, spi_data_out, spi_data_in;
  assign ws63_clk = spi_clk;
  assign ws63_cs_n = spi_cs_n;
  assign spi_data_in = ws63_data_out;
  assign ws63_data_in = spi_data_out;



/**
 * pll
 */
  wire clk_192MHz; 
  wire clk_16MHz; 

  Gowin_rPLL mPLL(
    .clkout(clk_192MHz), 
    .clkoutd(clk_16MHz), 
    .clkin(sys_clk) //input clkin, 27MHz
  );


/**
 * SPI clock
 */
  reg [2:0] clk_counter;
  always @(posedge clk_16MHz) begin
    clk_counter <= clk_counter + 1'b1;
  end	 

  wire op_clk = clk_counter[2]; //2MHz

/**
 * data to send
 */

  //12*32bit payload
  localparam NUM_OF_WORDS=12;

  wire [NUM_OF_WORDS*32-1:0] data_to_send;

/**
 * shift buffer
 */
  reg [NUM_OF_WORDS*32+2:0] shift_data_reg;
  reg [NUM_OF_WORDS*32+2:0] shift_clk_mask_reg;
  reg [NUM_OF_WORDS*32+2:0] shift_cs_n_reg;

  wire load_trigger;

  always @(posedge op_clk) begin
    if (load_trigger) begin
      shift_data_reg <= {2'b00, data_to_send,1'b0};
      shift_clk_mask_reg <= {2'b00, {NUM_OF_WORDS*32{1'b1}},1'b0};
      shift_cs_n_reg <= {2'b10, {NUM_OF_WORDS*32{1'b0}},1'b0};
    end else begin
      shift_data_reg <= {shift_data_reg[NUM_OF_WORDS*32+1:0], 1'b0};
      shift_clk_mask_reg <= {shift_clk_mask_reg[NUM_OF_WORDS*32+1:0], 1'b0};
      shift_cs_n_reg <= {shift_cs_n_reg[NUM_OF_WORDS*32+1:0], 1'b1};
    end	
  end	
  
  assign spi_clk = op_clk & shift_clk_mask_reg[NUM_OF_WORDS*32+2];
  assign spi_cs_n = shift_cs_n_reg[NUM_OF_WORDS*32+2];
  assign spi_data_out = shift_data_reg[NUM_OF_WORDS*32+2];
//


/**
 * load trigger
 */
  reg [23:0] count_reg;

  always @(negedge op_clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
      count_reg <= 24'd0;
    else
      count_reg <= count_reg + 1'b1;	
  end	
  //load_trigger is set by negedge of op_clk and with 1 op_clk width


//triggered 1024 times @2MHz //work
  assign load_trigger = (count_reg[10:0] == 20'b1);  


/**
 * MIC part
 */
  /**
   * mic clock
   */
  reg [11:0] mic_counter;
  always @(posedge clk_192MHz or negedge sys_rst_n) begin
      if (!sys_rst_n)
          mic_counter <= 12'd0;
      else
          mic_counter <= mic_counter + 1'd1;
  end

  wire clk_3072kHz_n = mic_counter[5];  //192M/64=3MHz
  wire clk_48kHz_n   = mic_counter[11]; //3M/64=48kHz

  assign mic_ck = clk_3072kHz_n;
  assign mic_ws = clk_48kHz_n;
  assign mic_lr = 1'b0;
  /**
   * receive mic data
   */
  reg [63:0] shift_reg;

  always @(posedge mic_ck) begin
      shift_reg <= {shift_reg[62:0], mic_data};	
  end	
      
  reg [63:0] data_reg;
  always  @(negedge mic_ws) begin
      data_reg <= shift_reg;
  end		

  wire[23:0] data_l = data_reg[62:39];	
  wire[23:0] data_r = data_reg[30:7];	    


  /**
   * shifted data buffer
   */
  reg[15:0] d_buf[0:47];
  always  @(posedge mic_ws) begin
    d_buf[47]<=d_buf[46];d_buf[46]<=d_buf[45];d_buf[45]<=d_buf[44];d_buf[44]<=d_buf[43];
    d_buf[43]<=d_buf[42];d_buf[42]<=d_buf[41];d_buf[41]<=d_buf[40];d_buf[40]<=d_buf[39];d_buf[39]<=d_buf[38];
    d_buf[38]<=d_buf[37];d_buf[37]<=d_buf[36];d_buf[36]<=d_buf[35];d_buf[35]<=d_buf[34];d_buf[34]<=d_buf[33];
    d_buf[33]<=d_buf[32];d_buf[32]<=d_buf[31];d_buf[31]<=d_buf[30];d_buf[30]<=d_buf[29];d_buf[29]<=d_buf[28];
    d_buf[28]<=d_buf[27];d_buf[27]<=d_buf[26];d_buf[26]<=d_buf[25];d_buf[25]<=d_buf[24];d_buf[24]<=d_buf[23];
    d_buf[23]<=d_buf[22];d_buf[22]<=d_buf[21];d_buf[21]<=d_buf[20];d_buf[20]<=d_buf[19];d_buf[19]<=d_buf[18];
    d_buf[18]<=d_buf[17];d_buf[17]<=d_buf[16];d_buf[16]<=d_buf[15];d_buf[15]<=d_buf[14];d_buf[14]<=d_buf[13];
    d_buf[13]<=d_buf[12];d_buf[12]<=d_buf[11];d_buf[11]<=d_buf[10];d_buf[10]<=d_buf[9];d_buf[9]<=d_buf[8];
    d_buf[8]<=d_buf[7];d_buf[7]<=d_buf[6];d_buf[6]<=d_buf[5];d_buf[5]<=d_buf[4];d_buf[4]<=d_buf[3];
    d_buf[3]<=d_buf[2];d_buf[2]<=d_buf[1];d_buf[1]<=d_buf[0];
    d_buf[0] <= data_l[23:8];
  end		

  assign data_to_send = {d_buf[47],d_buf[45],d_buf[43],d_buf[41],
    d_buf[39],d_buf[37],d_buf[35],d_buf[33],d_buf[31],
    d_buf[29],d_buf[27],d_buf[25],d_buf[23],d_buf[21],
    d_buf[19],d_buf[17],d_buf[15],d_buf[13],d_buf[11],
    d_buf[9] ,d_buf[7] ,d_buf[5] ,d_buf[3] ,d_buf[1]};
    

  //it's signed data    
  wire[22:0] l_amplitude = data_l[23] ? ((~data_l[22:0])+1'b1) : data_l[22:0];
  wire loud_voice = (l_amplitude[22:16]>=7'h07) ? 1'b1 : 1'b0;    

//led
  assign led = ~l_amplitude[22:17];


  
endmodule